package com.luo.demo.security.controller;

import com.luo.demo.sc.base.utils.JsonUtils;
import com.nimbusds.jose.util.JSONStringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import javax.annotation.Resource;

import java.util.HashMap;
import java.util.Map;

import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;


/**
 * REST服务 - Controller
 *
 * @author luohq
 * @date 2022-02-18
 */
@RestController
@Slf4j
public class RestSvcController {

	@GetMapping("/hello")
	public String hello(Authentication authentication) {
		log.info("hello Authentication: {}", JsonUtils.toJson(authentication));
		String reply = "Reply Hello, " + authentication.getName() + "!";
		log.info("cur reply: {}", reply);
		return reply;
	}

	@GetMapping("/authInfo")
	public Map<String, Object> authInfo(Authentication authentication) {
		log.info("get Authentication: class={}", authentication.getClass());
		log.info("get Authentication: {}", JsonUtils.toJson(authentication));
		Map<String, Object> resultMap = new HashMap<>(2);

		OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken) authentication;
		DefaultOidcUser oidcUser = (DefaultOidcUser) oAuth2AuthenticationToken.getPrincipal();
		resultMap.put("idToken", oidcUser.getIdToken().getTokenValue());
		resultMap.put("oidcUserInfo", oidcUser.getUserInfo().getClaims());
		resultMap.put("oidc.claims", oidcUser.getClaims());
		return resultMap;
	}


	@Resource
	private WebClient webClient;

	@Value("${spring.security.oauth2.resourceserver.resource1:http://oauth2-resource1:8090/articles}")
	private String resource1Uri;
	@Value("${spring.security.oauth2.resourceserver.resource2:http://oauth2-resource1:8091/articles}")
	private String resource2Uri;
	@Value("${spring.security.oauth2.authserver.resource1:http://oauth2-server:9000/api/articles}")
	private String authServerResourceUri;


	private final String clientRegistrationId = "luo-oauth2-client2";

	@GetMapping(value = "/resource1/articles1")
	public String[] getResource1Articles1(@RegisteredOAuth2AuthorizedClient(clientRegistrationId) OAuth2AuthorizedClient authorizedClient) {
		return this.getArticles1(this.resource1Uri, authorizedClient);
	}


	@GetMapping(value = "/resource1/articles2")
	public String[] getResource1Articles2() {
		return this.getArticles2(this.resource1Uri, clientRegistrationId);
	}

	@GetMapping(value = "/resource2/articles1")
	public String[] getResource2Articles1(@RegisteredOAuth2AuthorizedClient(clientRegistrationId) OAuth2AuthorizedClient authorizedClient) {
		return this.getArticles1(this.resource2Uri, authorizedClient);
	}


	@GetMapping(value = "/resource2/articles2")
	public String[] getResource2Articles2() {
		return this.getArticles2(this.resource2Uri, clientRegistrationId);
	}


	@GetMapping(value = "/authserver/articles1")
	public String[] getAuthserverArticles1() {
		return this.getArticles2(this.authServerResourceUri, clientRegistrationId);
	}


	@GetMapping(value = "/authserver/articles2")
	public String[] getArticles4() {
		return this.postArticles2(this.authServerResourceUri, clientRegistrationId);
	}

	private String[] getArticles1(String uri, OAuth2AuthorizedClient authorizedClient) {
		log.info("get articles1 uri: {} by OAuth2AuthorizedClient", uri, JsonUtils.toJson(authorizedClient));
		String[] articles = this.webClient
				.get()
				.uri(uri)
				.attributes(oauth2AuthorizedClient(authorizedClient))
				.retrieve()
				.bodyToMono(String[].class)
				.block();
		log.info("get articles1, result: {}", JsonUtils.toJson(articles));
		return articles;
	}

	private String[] getArticles2(String uri, String clientRegistrationId) {
		log.info("get articles2 uri: {} by clientId: {}", uri, clientRegistrationId);
		String[] articles = this.webClient
				.get()
				.uri(uri)
				.attributes(clientRegistrationId(clientRegistrationId))
				.retrieve()
				.bodyToMono(String[].class)
				.block();
		log.info("get articles2, result: {}", JsonUtils.toJson(articles));
		return articles;
	}

	private String[] postArticles2(String uri, String clientId) {
		log.info("post articles2 uri: {} by clientId: {}", uri, clientId);
		String[] articles = this.webClient
				.post()
				.uri(uri)
				.attributes(clientRegistrationId(clientId))
				.retrieve()
				.bodyToMono(String[].class)
				.block();
		log.info("post articles2, result: {}", JsonUtils.toJson(articles));
		return articles;
	}



}
